package com.wa.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.wa.pojo.BaseResponse;
import com.wa.pojo.GenericResp;
import com.wa.pojo.Page;
import com.wa.pojo.SchemeQuery;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.GraphQLError;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * GraphqlController. Handle request for GraphQL
 *
 * @author xuxd
 * @date 2021-06-03 11:17:58
 * @description GraphqlController. Handle request for GraphQL
 **/
@RestController
@RequestMapping("/graphql")
@Slf4j
public class GraphqlController {

    @Resource
    private GraphQL graphQL;

    @PostMapping
    public GenericResp<Object> route(@RequestBody SchemeQuery schemeQuery, HttpServletRequest request, HttpServletResponse response) throws Exception {
        GenericResp<Object> resp = new GenericResp();
        // 参数校验
        if (schemeQuery == null || StrUtil.isBlank(schemeQuery.getQuery())) {
            resp.setCode(BaseResponse.ERROR_RESULT.getResponseCode());
            resp.setMessage("参数为空！");
            return resp;
        }
        //分页参数
        Page<Object> page = new Page<>();
        // 额外参数
        Map<String, Object> rootMap = schemeQuery.getExtraParam();
        if (rootMap == null) {
            rootMap = new HashMap<>(16);
        } else {
            page.setParam(rootMap.get("param"));
            page.setExtraParam((Map<String, Object>) rootMap.get("extraParam"));
            page.setPageNo(Convert.toInt(rootMap.get("pageNo"),1));
            page.setPageSize(Convert.toInt(rootMap.get("pageSize"),10));
        }
        // 获取用户id
//        String userId = this.getUserId(request);
//        rootMap.put(DingTalkConstant.FIELD_USER_ID, userId);
        // 查询条件（1.增加code和message）
        String query = schemeQuery.getQuery();
        if (StrUtil.isNotEmpty(query)) {
            Pattern p = Pattern.compile("data\\s*\\{");
            Matcher m = p.matcher(query);
            query = m.replaceFirst("code,message,data{");
        }
        ExecutionInput executionInput = ExecutionInput.newExecutionInput()
                .context(page)
                .variables(null)
                .root(rootMap)
                .query(query)
                .build();
        ExecutionResult executionResult = graphQL.execute(executionInput);
        List<GraphQLError> graphQLErrorList = executionResult.getErrors();
        if (CollUtil.isNotEmpty(graphQLErrorList)) {
            log.error("调用接口异常:" + graphQLErrorList);
            resp.setCode(BaseResponse.ERROR_RESULT.getResponseCode());
            resp.setMessage(graphQLErrorList.stream().map(graphQLError -> graphQLError.getMessage()).collect(Collectors.joining("|")));
            return resp;
        }
        // 设置响应数据
        this.setResponseData(executionResult, resp);

        return resp;
    }

    /**
     * 设置响应数据
     *
     * @param executionResult
     * @param resp
     * @throws Exception
     */
    private void setResponseData(ExecutionResult executionResult, GenericResp<Object> resp) throws Exception {
        if (executionResult == null || executionResult.getData() == null) {
            return;
        }
        if (!(executionResult.getData() instanceof LinkedHashMap)) {
            return;
        }
        LinkedHashMap linkedHashMap = executionResult.getData();
        if (CollUtil.isEmpty(linkedHashMap)) {
            return;
        }
        Object value = linkedHashMap.values().stream().findFirst().get();
        if (!(value instanceof LinkedHashMap)) {
            return;
        }
        LinkedHashMap findLinkedHashMap = (LinkedHashMap) value;
        if (CollUtil.isEmpty(findLinkedHashMap)) {
            return;
        }
        // 返回异常信息处理
        int code = Convert.toInt(findLinkedHashMap.get("code"));
        if (code != BaseResponse.SUCCESS_RESULT.getResponseCode()) {
            resp.setCode(code);
            resp.setMessage(String.class.cast(findLinkedHashMap.get("message")));
        }
        if (findLinkedHashMap.containsKey("pageNo")) {
            resp.setData(value);
            return;
        }
        resp.setData(findLinkedHashMap.get("data"));
        return;
    }
}
